/*
 * @Description: 自定义插件：全局toast插件
 * @Author: laoyuan
 * @Date: 2023-04-17 07:43:37
 */
import ToastComponent from './loading.vue';
import { createVNode, render } from 'vue';
import type { App } from 'vue';

type Options = {
  msg: string;
  duration?: number;
  visible?: boolean;
} & Recordable;

const Toast = {
  // 当main.ts执行到app.use(toast)代码(安装插件)时，会执行这个install函数
  install(app: App) {
    // 是否存在toast，防止toast在未销毁前，连续点击按钮生成多个toast
    let isToast = false;
    // 默认配置
    const opt: Options = reactive({
      msg: 'hello toast',
      duration: 3000,
    });
    /**
     *  1.实例化并绑定组件
     */
    function renderDom() {
      // 如果toast不存在，则开始创建toast
      if (!isToast) {
        isToast = true;
        // createVNode vue提供的底层方法,可以给我们组件创建一个虚拟DOM
        const vNode = createVNode(ToastComponent, { message: opt.msg });
        /**
         *  2.将挂载的Node添加到body中
         */
        // render 把我们的Vnode生成真实DOM,并且挂载到指定节点
        render(vNode, document.body);
      }
    }

    // 删除toast
    function removeToast() {
      setTimeout(() => {
        const el = document.querySelector('.toast-container') as HTMLElement;
        // 清空节点
        render(null, document.body);
        el && el.remove();
        isToast = false;
      }, opt.duration);
    }

    /**
     *  3.定义全局插件的方法
     */
    // 注入一个全局可用的 $toast() 方法, 这个函数就能在任意模板中可以全局调用
    app.config.globalProperties.$toast = (options: Recordable | string) => {
      if (typeof options === 'object') {
        for (const key in options) {
          opt[key] = options[key];
        }
      } else {
        opt.msg = options;
      }
      renderDom();
      removeToast();
    };
  },
};

export default Toast;
